package me.ymfs.springboot.guice.aop;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.common.base.Stopwatch;
import lombok.extern.slf4j.Slf4j;
import me.ymfs.springboot.guice.util.RandomStringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Slf4j
public class LogAdvice {

    private final Stopwatch stopwatch = Stopwatch.createStarted();

    @Around("@annotation(logged)")
    public Object aroundLogger(ProceedingJoinPoint joinPoint, Logged logged) throws Throwable {
        String uuid = RandomStringUtils.uuid32();
        log.info("[{}] EXEC METHOD: {} ==> [{}] Start", uuid, joinPoint.getSignature().toString(),
                logged.desc());
        if (logged.printParams())
            log.info("[{}] params ==> {}", uuid, JSON.toJSONString(joinPoint.getArgs(),
                    SerializerFeature.IgnoreNonFieldGetter));
        else
            log.debug("[{}] params ==> {}", uuid, JSON.toJSONString(joinPoint.getArgs(),
                    SerializerFeature.IgnoreNonFieldGetter));
        this.stopwatch.reset().start();
        try {
            Object ret = joinPoint.proceed();
            if (logged.printPesult())
                log.info("[{}] result ==> {}", uuid, JSON.toJSONString(ret,
                        SerializerFeature.IgnoreNonFieldGetter));
            log.info("[{}] EXEC METHOD: {} ==> [{}] End", uuid, joinPoint.getSignature().toString(),
                    logged.desc());
            return ret;
        } catch (Throwable t) {
            log.error("[{}] EXEC METHOD: {} ==> [{}] Exception, Cause by: [{}]", uuid, joinPoint.getSignature().toString(),
                    logged.desc(), t.getMessage(), t);
            throw t;
        } finally {
            if (logged.spendTime()) {
                this.stopwatch.stop();
                log.info("[{}] cost time ==> {}", uuid, this.stopwatch);
            }
        }
    }

}
